package cn.edu.zzuli.stack;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.regex.PatternSyntaxException;

public class PolandNotation {

    public static void main(String[] args) {
        //使用后缀表达式(逆波兰)来进行 表达式的计算
        //为了区别 多位数，我们使用空格来将 符合和数值分割
        String nifix = "1 + ( ( 2 + 3 ) * 4 ) - 5";
        //String expr = "3 4 + 5 * 6 -";
        List<String> expr = nifixToPostfix(processExpr(nifix));
        //System.out.println(expr);
        float result = getResult(expr);
        System.out.println(result);
    }

    public static List<String> nifixToPostfix(List<String> nifix) {
        //存放符号
        LinkStack<String> stack = new LinkStack<>();
        //用来代替栈s2，存放结果,因为我们的 s2栈并没有pop操作，所以可以代替。
        List<String> postfix = new ArrayList<>();
        nifix.forEach(v -> {
            //判断是符号还是数字
            if (isOperator(v)) {
                //如果栈为空 或者 栈顶为 (
                if (stack.isEmpety() || stack.top().equals("(") || v.equals("(")) {
                    stack.push(v);
                }
                else if (v.equals(")")) {
                    //依次弹出
                    while (!stack.top().equals("(")) {
                        postfix.add(stack.pop());
                    }
                    //弹出 (
                    stack.pop();
                }
                else{
                    //判断优先级 <= 得情况
                    while (!stack.isEmpety() && priority(v) <= priority(stack.top())) {
                        postfix.add(stack.pop());
                    }
                    //此时栈顶有元素的话，已经比当前运算符的优先级高了
                    stack.push(v);
                }
            }else {
                //数字直接入栈
                postfix.add(v);
            }
        });

        while (!stack.isEmpety()) {
            postfix.add(stack.pop());
        }

        return postfix;
    }

    public static List<String> processExpr(String expr) {
        String[] split = expr.split(" ");
        List<String> list = new ArrayList<>();
        //将分割的数组加入到 list中
        Arrays.stream(split).forEach(list::add);
        return list;
    }

    public static float getResult(List<String> expr) {
        LinkStack<Float> stack = new LinkStack<>();
        //开始扫描 表达式
        expr.forEach(v -> {
            //首先判断是数字还是字符
            if (!isOperator(v)) {
                //不是符号的话直接入栈
                stack.push(Float.parseFloat(v));
            }else {
                //是字符的话，从栈中pop出两个数值，然后进行计算
                float res = cal(stack.pop(), stack.pop(), v);
                //再将计算出的数值入栈
                stack.push(res);
            }
        });

        return stack.pop();
    }

    public static int priority(String oper) {
        if (oper.equals("*") || oper.equals("/")) {
            return 10;
        } else if (oper.equals("+") || oper.equals("-")) {
            return 5;
        }

        return -1;
    }
    public static boolean isOperator(String val) {
        return  val.equals("+") ||
                val.equals("-") ||
                val.equals("*") ||
                val.equals("/") ||
                val.equals("(") ||
                val.equals(")");
    }

    public static float cal(float num1, float num2, String oper) {
        float res = 0;
        switch (oper) {
            case "+" :
                res = num2 + num1;
                break;
            case "-" :
                res = num2 - num1;
                break;
            case "*" :
                res = num2 * num1;
                break;
            case "/" :
                res = num2 / num1;
                break;
        }

        return res;
    }

}
